package org.newlucene.suggest;

import java.io.IOException;
import java.util.BitSet;

import org.newlucene.core.document.Document;
import org.newlucene.core.index.IndexReader;
import org.newlucene.core.search.HitCollector;
import org.newlucene.core.search.HitQueue;
import org.newlucene.core.search.ScoreDoc;

public class SuggestHitCollector implements HitCollector
{
	private HitQueue hq;
	private IndexReader ir;
	private int capacity;
	private int totalHits = 0;
	private String normInputWord;
	private EditDistance dist;
	
	// the maximum distance ratio that the suggested word must be less than.
	// the distance ratio is calculated as follows:
	// DISTANCE / MIN(SuggestWordLength, InputWordLength) 
	private static float MAX_DIST_RATIO = 0.4f;	
	
	public SuggestHitCollector(String inputWord, IndexReader indexReader, int capacity) throws IOException
	{
		hq = new HitQueue(capacity);
		this.ir = indexReader;
		this.capacity = capacity;
		this.normInputWord = inputWord.replaceAll("[\\s]+", "");
		dist = new EditDistance(normInputWord);
	}
	
	public final void collect(int doc, float score) throws IOException
	{
		Document document = ir.document(doc);
		
		String suggestWord = document.get("keyword").replaceAll("[\\s]+", "");

		// check if this suggestWord is less than the max dist ratio
		float distRatio = (float) dist.getDistance(suggestWord) / (float) Math.min(suggestWord.length(), normInputWord.length());
		if (distRatio > MAX_DIST_RATIO)
		{
			return;
		}
			
		score = score / (float) dist.getDistance(suggestWord);
		
		// get the keyword freq
		int freq = Integer.parseInt(document.get("freq"));
		// factor in the keyword freq
		score = score * (freq / (float) Integer.MAX_VALUE);
		//System.out.println(suggestWord + "    " + score + " " + freq);

//		double lenDiff = Math.abs(keyword.length() - inputWord.length()) * 1.0d;
//		score = score / (float) (Math.log(lenDiff) + 1);
		
		totalHits++;
		hq.put(new ScoreDoc(doc, score)); // update hit queue
		// if hit queue overfull
		if (hq.size() > capacity)
		{ 
			// remove lowest in hit queue
			hq.pop();			
		}
	}
	
	public int getTotalHits()
	{
		return totalHits;
	}
	
	public ScoreDoc[] getScoreDocs()
	{
		ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()];
		int i = scoreDocs.length - 1;
		while (hq.top() != null)
		{
			scoreDocs[i] = (ScoreDoc) hq.pop();
			i--;
		}
		return scoreDocs; 
	}
	
	public int getNumScoreDocs()
	{
		return hq.size();
	}
	
	public int getCapacity()
	{
		return capacity;
	}
}